package xlog

import (
	"fmt"
	"gitee.com/xiedongji/antgo/core"
	"gitee.com/xiedongji/antgo/helper/xfile"
	"gitee.com/xiedongji/antgo/helper/xreopen"
	"github.com/rs/zerolog"
	"io"
	"log"
	"os"
	"path/filepath"
	"sync"
	"time"
)

/* ============================================================ *
 * 功能:日志二次封装
 * 描述:项目组件加载、配置文件的初始化
 * ============================================================ */
const cptName = "log"

type Instance struct{}

func (i *Instance) GetName() string {
	return cptName
}

// 加载日志相关的配置信息
func (i *Instance) Run() error {
	instance = i
	// 读取配置到变量中
	core.GetCptConfig(cptName, i)
	// 设置日志级别
	if core.RunEnv == core.DevEnv {
		zerolog.SetGlobalLevel(zerolog.DebugLevel)
	} else {
		zerolog.SetGlobalLevel(zerolog.InfoLevel)
	}

	return nil
}

var instance *Instance
var loggerLock sync.Mutex
var loggerWriters = make(map[string]xreopen.Writer)

// ====================== 业务板块 ======================
func Logger(logFilename string, tag string) *zerolog.Logger {
	logDir := filepath.Join(core.WorkDir, "logs")
	// 多重判断 解决 操作日志 线程安全问题
	if _, ok := loggerWriters[logFilename]; !ok {
		// 匿名函数
		func(loggerWriters map[string]xreopen.Writer) {
			loggerLock.Lock()
			if _, ok = loggerWriters[logFilename]; ok {
				return
			}
			defer loggerLock.Unlock()
			// 创建文件夹
			xfile.CreateFolder(logDir, true)
			logFile := filepath.Join(logDir, fmt.Sprintf("%s.log", logFilename))
			// 开启日志
			if fw, err := xreopen.NewFileWriter(logFile); err != nil {
				log.Fatalf("%s touch %s log file %s err : %v", "AntMan", logFilename, logFile, err)
			} else {
				loggerWriters[logFilename] = fw
			}
		}(loggerWriters)
	}

	if core.RunEnv == core.DevEnv {
		// 开发环境 日志同时输出到控制台和文件
		multiWriter := io.MultiWriter(
			zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.Kitchen, NoColor: false}, // 输出到控制台
			loggerWriters[logFilename], //输出到日志
		)
		logger := zerolog.New(multiWriter).With().Str("tag", tag).Timestamp().Caller().Logger()
		return &logger
	} else {
		logger := zerolog.New(loggerWriters[logFilename]).With().Str("tag", tag).Timestamp().Logger()
		return &logger
	}

}

// 分割日志
func SetCuttingSignal(sig os.Signal) {
	core.SignalBindFunHandler(func(sig os.Signal) {
		for _, logW := range loggerWriters {
			logW.Reopen()
		}
	}, sig)
}
